/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* define to prevent recursive inclusion -------------------------------------*/
#ifndef __PONY_HAL_MTD_H__
#define __PONY_HAL_MTD_H__

/* includes (standard library, system) ---------------------------------------*/
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
/* includes (local) ----------------------------------------------------------*/
#include "hal.h"

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

/* defines -------------------------------------------------------------------*/
/* typedefs ------------------------------------------------------------------*/

/* ioctl cmds */
enum hal_mtd_cmd {
    /* ioctl(mtd, cmd, size_t *) */
    HAL_MTD_CMD_GET_ID,     /* flash id */
    HAL_MTD_CMD_GET_DEV_ID, /* device id */
    /* ioctl(mtd, cmd) */
    HAL_MTD_CMD_LOCK,
    HAL_MTD_CMD_UNLOCK,
    HAL_MTD_CMD_CHIP_ERASE,
    /* ioctl(mtd, cmd, size_t) */
    HAL_MTD_CMD_SECTOR_ERASE, /* erase the sector of the specified index */
    /* ioctl(mtd, cmd, pos, size_t *) */
    HAL_MTD_CMD_GET_SECTOR_SIZE, /* pos is used to get unfixed sector size */
    /* expand */
    HAL_MTD_CMD_CUSTOM,
};

typedef struct hal_mtd hal_mtd_t;

typedef struct hal_mtd_methods {
    int (*erase_block)(hal_mtd_t *, size_t startblock, size_t nblocks); /* erase blocks */
    int (*read_block)(hal_mtd_t *, size_t startblock, size_t nblocks,
                      uint8_t *buf); /* read blocks */
    int (*write_block)(hal_mtd_t *, size_t startblock, size_t nblocks,
                       const uint8_t *buf);                                   /* write blocks */
    int (*erase)(hal_mtd_t *, size_t pos, size_t nbytes);                     /* erase bytes */
    int (*read)(hal_mtd_t *, size_t pos, size_t nbytes, uint8_t *buf);        /* read bytes */
    int (*write)(hal_mtd_t *, size_t pos, size_t nbytes, const uint8_t *buf); /* write bytes */
    int (*ioctl)(hal_mtd_t *, int, va_list);                                  /* ioctl */
} hal_mtd_methods_t;

struct hal_mtd {
    hal_dev_t parent;
    k_mutex_t lock;
    size_t start_addr;
    size_t page_size;    /* page size (bytes) */
    uint64_t total_size; /* total storage size (bytes) */
    const hal_mtd_methods_t *methods;
};

/* macro ---------------------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* externs -------------------------------------------------------------------*/

extern hal_mtd_t *hal_mtd_open(const char *name);
extern int hal_mtd_close(hal_mtd_t *mtd);
extern int hal_mtd_erase_block(hal_mtd_t *mtd, size_t startblock, size_t nblocks);
extern int hal_mtd_read_block(hal_mtd_t *mtd, size_t startblock, size_t nblocks, uint8_t *buf);
extern int hal_mtd_write_block(hal_mtd_t *mtd, size_t startblock, size_t nblocks,
                               const uint8_t *buf);
extern int hal_mtd_erase(hal_mtd_t *mtd, size_t pos, size_t nbytes);
extern int hal_mtd_read(hal_mtd_t *mtd, size_t pos, size_t nbytes, uint8_t *buf);
extern int hal_mtd_write(hal_mtd_t *mtd, size_t pos, size_t nbytes, const uint8_t *buf);
extern int hal_mtd_write_safe(hal_mtd_t *mtd, size_t pos, size_t nbytes, const uint8_t *buf);
extern int hal_mtd_erase_write(hal_mtd_t *mtd, size_t pos, size_t nbytes, const uint8_t *buf);
extern int hal_mtd_ioctl(hal_mtd_t *mtd, int cmd, ...);
extern int hal_mtd_register(hal_mtd_t *mtd, const char *name, const hal_mtd_methods_t *methods,
                            uintptr_t data);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* __PONY_HAL_MTD_H__ */
